home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / UNIXTOOL / M4SRC / _files / _M4 / Serv._C < prev    next >
Encoding:
Text File  |  1989-10-15  |  13.3 KB  |  479 lines

  1. /*
  2.  * serv.c
  3.  * Facility: m4 macro processor
  4.  * by: oz
  5.  */
  6.  
  7. #include "mdef.h"
  8. #include "extr.h" 
  9.  
  10. #include <string.h>
  11. #include <stdlib.h>
  12.  
  13. char *dumpfmt = "`%s'\t`%s'\n"; /* format string for dumpdef   */
  14.  
  15. /*
  16.  * expand - user-defined macro expansion
  17.  *
  18.  */
  19. void expand (char *argv[], int argc)
  20. {
  21.         register char *t;
  22.         register char *p;
  23.         register int  n;
  24.         register int  argno;
  25.  
  26.         t = argv[0];    /* defn string as a whole */
  27.         p = t;
  28.         while (*p)
  29.                 p++;
  30.         p--;            /* last character of defn */
  31.         while (p > t) {
  32.                 if (*(p-1) != ARGFLAG)
  33.                         putback(*p);
  34.                 else {
  35.                         switch (*p) {
  36.  
  37.                         case '#':
  38.                                 pbnum(argc-2);
  39.                                 break;
  40.                         case '0':
  41.                         case '1':
  42.                         case '2':
  43.                         case '3':
  44.                         case '4':
  45.                         case '5':
  46.                         case '6':
  47.                         case '7':
  48.                         case '8':
  49.                         case '9':
  50.                                 if ((argno = *p - '0') < argc-1)
  51.                                         pbstr(argv[argno+1]);
  52.                                 break;
  53.                         case '*':
  54.                                 for (n = argc - 1; n > 2; n--) {
  55.                                         pbstr(argv[n]);
  56.                                         putback(',');
  57.                                 }
  58.                                 pbstr(argv[2]);
  59.                                 break;
  60.                         case '@':
  61.                                 for (n = argc - 1; n > 2; n--) {
  62.                                     putback(rquote);
  63.                                         pbstr(argv[n]);
  64.                                         putback(lquote);
  65.                                         putback(',');
  66.                                 }
  67.                 putback(rquote);
  68.                 pbstr(argv[2]);
  69.                 putback(lquote);
  70.                                 break;
  71.                         default :
  72.                                 putback(*p);
  73.                                 break;
  74.                         }
  75.                         p--;
  76.                 }
  77.                 p--;
  78.         }
  79.         if (p == t)         /* do last character */
  80.                 putback(*p);
  81. }
  82.  
  83. /*
  84.  * dodefine - install definition in the table
  85.  *
  86.  */
  87. void dodefine (char *name, char *defn)
  88. {
  89.         register ndptr p;
  90.  
  91.         if (!*name)
  92.                 error("M4: Null definition");
  93.         if (strcmp(name, defn) == 0)
  94.                 error("M4: Recursive definition");
  95.         if ((p = lookup(name)) == nil)
  96.                 p = addent(name);
  97.         else if (p->defn != null)
  98.                 free(p->defn);
  99.         if (!*defn)
  100.                 p->defn = null;
  101.         else
  102.                 p->defn = strsave(defn);
  103.         p->type = MACRTYPE;
  104. }
  105.  
  106. /*
  107.  * dodefn - push back a quoted definition of
  108.  *      the given name.
  109.  */
  110.  
  111. void dodefn (char *name)
  112. {
  113.         register ndptr p;
  114.  
  115.         if ((p = lookup(name)) != nil && p->defn != null) {
  116.                 putback(rquote);
  117.                 pbstr(p->defn);
  118.                 putback(lquote);
  119.         }
  120. }
  121.      
  122. /*
  123.  * dopushdef - install a definition in the hash table
  124.  *      without removing a previous definition. Since
  125.  *      each new entry is entered in *front* of the
  126.  *      hash bucket, it hides a previous definition from
  127.  *      lookup.
  128.  */
  129. void dopushdef (char *name, char *defn)
  130. {
  131.         register ndptr p;
  132.  
  133.         if (!*name)
  134.                 error("M4: Null definition");
  135.         if (strcmp(name, defn) == 0)
  136.                 error("M4: Recursive definition");
  137.         p = addent(name);
  138.         if (!*defn)
  139.                 p->defn = null;
  140.         else
  141.                 p->defn = strsave(defn);
  142.         p->type = MACRTYPE;
  143. }
  144.  
  145. /*
  146.  * dodumpdef - dump the specified definitions in the hash
  147.  *      table to stderr. If nothing is specified, the entire
  148.  *      hash table is dumped.
  149.  *
  150.  */
  151. void dodump (char *argv[], int argc)
  152. {
  153.         register int n;
  154.         ndptr p;
  155.  
  156.         if (argc > 2) {
  157.                 for (n = 2; n < argc; n++)
  158.                         if ((p = lookup(argv[n])) != nil)
  159.                                 fprintf(stderr, dumpfmt, p->name,
  160.                                 p->defn);
  161.         }
  162.         else {
  163.                 for (n = 0; n < HASHSIZE; n++)
  164.                         for (p = hashtab[n]; p != nil; p = p->nxtptr)
  165.                                 fprintf(stderr, dumpfmt, p->name,
  166.                                 p->defn);
  167.         }
  168. }
  169.  
  170. /*
  171.  * doifelse - select one of two alternatives - loop.
  172.  *
  173.  */
  174. void doifelse (char *argv[], int argc)
  175. {
  176.         forever
  177.         {
  178.                 if (strcmp(argv[2], argv[3]) == 0)
  179.                         pbstr(argv[4]);
  180.                 else if (argc == 6)
  181.                         pbstr(argv[5]);
  182.                 else if (argc > 6) {
  183.                         argv += 3;
  184.                         argc -= 3;
  185.                         continue;
  186.                 }
  187.                 break;
  188.         }
  189. }
  190.  
  191. /*
  192.  * doinclude - include a given file.
  193.  *
  194.  */
  195. int doincl (char *ifile)
  196. {
  197.         if (ilevel+1 == MAXINP)
  198.                 error("M4: Too many include files");
  199.  
  200.     /* Save the position in this input file, and close it */
  201.     if (INFP != stdin)
  202.     {
  203.         INPTR = ftell(INFP);
  204.         (void) fclose(INFP);
  205.     }
  206.  
  207.     ++ilevel;
  208.  
  209.         if ((INFP = fopen(ifile, "r")) != NULL)
  210.         {
  211.         INNAME = ifile;
  212.         INPTR = 0L;
  213.                 return (1);
  214.         }
  215.         else
  216.         {
  217.             --ilevel;
  218.                 return (0);
  219.         }
  220. }
  221.  
  222. #ifdef EXTENDED
  223. /*
  224.  * dopaste - include a given file without any
  225.  *           macro processing.
  226.  */
  227. int dopaste (char *pfile)
  228. {
  229.         FILE *pf;
  230.         register int c;
  231.  
  232.         if ((pf = fopen(pfile, "r")) != NULL)
  233.         {
  234.             if (active != NULL)
  235.             {
  236.                     while((c = getc(pf)) != EOF)
  237.                             putc(c, active);
  238.                 }
  239.  
  240.                 (void) fclose(pf);
  241.                 return(1);
  242.         }
  243.         else
  244.                 return(0);
  245. }
  246. #endif
  247.  
  248. /*
  249.  * dochq - change quote characters
  250.  *
  251.  */
  252. void dochq (char *argv[], int argc)
  253. {
  254.         if (argc > 2) {
  255.                 if (*argv[2])
  256.                         lquote = *argv[2];
  257.                 if (argc > 3) {
  258.                         if (*argv[3])
  259.                                 rquote = *argv[3];
  260.                 }
  261.                 else
  262.                         rquote = lquote;
  263.         }
  264.         else {
  265.                 lquote = LQUOTE;
  266.                 rquote = RQUOTE;
  267.         }
  268. }
  269.  
  270. /*
  271.  * dochc - change comment characters
  272.  *
  273.  */
  274. void dochc (char *argv[], int argc)
  275. {
  276.         if (argc > 2) {
  277.                 if (*argv[2])
  278.                         scommt = *argv[2];
  279.                 if (argc > 3) {
  280.                         if (*argv[3])
  281.                                 ecommt = *argv[3];
  282.                 }
  283.                 else
  284.                         ecommt = ECOMMT;
  285.         }
  286.         else {
  287.                 scommt = SCOMMT;
  288.                 ecommt = ECOMMT;
  289.         }
  290. }
  291.  
  292. /*
  293.  * dodivert - divert the output to a temporary file
  294.  *
  295.  */
  296. void dodiv (int n)
  297. {
  298.     /* Close the current output stream */
  299.     (void) fclose (outfile[oindex].fp);
  300.     outfile[oindex].fp = NULL;
  301.  
  302.     /* Consider the two special cases:
  303.      *    divert(n) ignores all output, if n < 0 or n > MAXOUT
  304.      *    divert(0) diverts to stdout directly.
  305.      */
  306.  
  307.         if (n < 0 || n >= MAXOUT)
  308.         {
  309.                 oindex = -1;
  310.                 active = NULL;
  311.                 return;
  312.         }
  313.  
  314.     if (n == 0)
  315.     {
  316.         oindex = 0;
  317.         active = stdout;
  318.         return;
  319.     }
  320.  
  321.     /* Prepare the new output stream */
  322.         if (!outfile[n].ptr)
  323.         {
  324.                 *m4divnum = n + '0';
  325.                 if ((outfile[n].fp = fopen(m4temp, "w")) == NULL)
  326.                         error("M4: Cannot divert into diversion %d", n);
  327.                 outfile[n].name = strsave(m4temp);
  328.                 outfile[n].ptr  = 1L;
  329.         }
  330.     else
  331.         {
  332.                 if ((outfile[n].fp = fopen(outfile[n].name, "a")) == NULL)
  333.                         error("M4: Cannot divert into diversion %d", n);
  334.         }
  335.  
  336.         oindex = n;
  337.         active = outfile[n].fp;
  338. }
  339.  
  340. /*
  341.  * doundivert - undivert a specified output, or all
  342.  *              other outputs, in numerical order.
  343.  */
  344. void doundiv (char *argv[], int argc)
  345. {
  346.         register int ind;
  347.         register int n;
  348.  
  349.         if (argc > 2) {
  350.                 for (ind = 2; ind < argc; ind++) {
  351.                         n = atoi(argv[ind]);
  352.                         if (n > 0 && n < MAXOUT && outfile[n].ptr)
  353.                                 getdiv(n);
  354.  
  355.                 }
  356.         }
  357.         else
  358.                 for (n = 1; n < MAXOUT; n++)
  359.                         if (outfile[n].ptr)
  360.                                 getdiv(n);
  361. }
  362.  
  363. /*
  364.  * dosub - select substring
  365.  *
  366.  */
  367. void dosub (char *argv[], int argc)
  368. {
  369.         register char *ap, *fc, *k;
  370.         register int nc;
  371.  
  372.         if (argc < 5)
  373.                 nc = MAXTOK;
  374.         else
  375. #ifdef EXPR
  376.                 nc = expr(argv[4]);
  377. #else
  378.         nc = atoi(argv[4]);
  379. #endif
  380.         ap = argv[2];                   /* target string */
  381. #ifdef EXPR
  382.         fc = ap + expr(argv[3]);        /* first char */
  383. #else
  384.         fc = ap + atoi(argv[3]);        /* first char */
  385. #endif
  386.         if (fc >= ap && fc < ap+strlen(ap))
  387.                 for (k = fc+min(nc,strlen(fc))-1; k >= fc; k--)
  388.                         putback(*k);
  389. }
  390.  
  391. /*
  392.  * map:
  393.  * map every character of s1 that is specified in from
  394.  * into s3 and replace in s. (source s1 remains untouched)
  395.  *
  396.  * This is a standard implementation of map(s,from,to) function of ICON 
  397.  * language. Within mapvec, we replace every character of "from" with 
  398.  * the corresponding character in "to". If "to" is shorter than "from", 
  399.  * than the corresponding entries are null, which means that those 
  400.  * characters dissapear altogether. Furthermore, imagine 
  401.  * map(dest, "sourcestring", "srtin", "rn..*") type call. In this case, 
  402.  * `s' maps to `r', `r' maps to `n' and `n' maps to `*'. Thus, `s' 
  403.  * ultimately maps to `*'. In order to achieve this effect in an efficient 
  404.  * manner (i.e. without multiple passes over the destination string), we 
  405.  * loop over mapvec, starting with the initial source character. if the 
  406.  * character value (dch) in this location is different than the source 
  407.  * character (sch), sch becomes dch, once again to index into mapvec, until 
  408.  * the character value stabilizes (i.e. sch = dch, in other words 
  409.  * mapvec[n] == n). Even if the entry in the mapvec is null for an ordinary 
  410.  * character, it will stabilize, since mapvec[0] == 0 at all times. At the 
  411.  * end, we restore mapvec* back to normal where mapvec[n] == n for 
  412.  * 0 <= n <= 127. This strategy, along with the restoration of mapvec, is 
  413.  * about 5 times faster than any algorithm that makes multiple passes over 
  414.  * destination string.
  415.  *
  416.  */
  417.      
  418. void map (char *dest, char *src, char *from, char *to)
  419. {
  420.         register char *tmp;
  421.         register char sch, dch;
  422.         static char mapvec[256] = {
  423.                  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,
  424.                 10,  11,  12,  13,  14,  15,  16,  17,  18,  19,
  425.                 20,  21,  22,  23,  24,  25,  26,  27,  28,  29,
  426.                 30,  31,  32,  33,  34,  35,  36,  37,  38,  39,
  427.                 40,  41,  42,  43,  44,  45,  46,  47,  48,  49,
  428.                 50,  51,  52,  53,  54,  55,  56,  57,  58,  59,
  429.                 60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
  430.                 70,  71,  72,  73,  74,  75,  76,  77,  78,  79,
  431.                 80,  81,  82,  83,  84,  85,  86,  87,  88,  89,
  432.                 90,  91,  92,  93,  94,  95,  96,  97,  98,  99,
  433.                100, 101, 102, 103, 104, 105, 106, 107, 108, 109,
  434.                110, 111, 112, 113, 114, 115, 116, 117, 118, 119,
  435.                120, 121, 122, 123, 124, 125, 126, 127, 128, 129,
  436.                130, 131, 132, 133, 134, 135, 136, 137, 138, 139,
  437.                140, 141, 142, 143, 144, 145, 146, 147, 148, 149,
  438.                150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
  439.                160, 161, 162, 163, 164, 165, 166, 167, 168, 169,
  440.                170, 171, 172, 173, 174, 175, 176, 177, 178, 179,
  441.                180, 181, 182, 183, 184, 185, 186, 187, 188, 189,
  442.                190, 191, 192, 193, 194, 195, 196, 197, 198, 199,
  443.                200, 201, 202, 203, 204, 205, 206, 207, 208, 209,
  444.                210, 211, 212, 213, 214, 215, 216, 217, 218, 219,
  445.                220, 221, 222, 223, 224, 225, 226, 227, 228, 229,
  446.                230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
  447.                240, 241, 242, 243, 244, 245, 246, 247, 248, 249,
  448.                250, 251, 252, 253, 254, 255
  449.         };
  450.  
  451.         if (*src) {
  452.                 tmp = from;
  453.     /*
  454.      * create a mapping between "from" and "to"
  455.      */
  456.                 while (*from)
  457.                         mapvec[*from++] = (*to) ? *to++ : (char) 0;
  458.      
  459.                 while (*src) {
  460.                         sch = *src++;
  461.                         dch = mapvec[sch];
  462.                         while (dch != sch) {
  463.                                 sch = dch;
  464.                                 dch = mapvec[sch];
  465.                         }
  466.                         if ((*dest = dch) != 0)
  467.                                 dest++;
  468.                 }
  469.     /*
  470.      * restore all the changed characters
  471.      */
  472.                 while (*tmp) {
  473.                         mapvec[*tmp] = *tmp;
  474.                         tmp++;
  475.                 }
  476.         }
  477.         *dest = (char) 0;
  478. }
  479.